package net.towee.client.com.repo.presenter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import net.towee.client.com.repo.RepositoryNodeSelector;
import net.towee.client.managers.AccountHelper;
import net.towee.client.managers.NodesManager;
import net.towee.model.account.AccountGroup;
import net.towee.model.group.GroupIdentity;
import net.towee.model.repo.NodeData;
import net.towee.model.repo.impl.NodeDataImpl;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.HasSelectionHandlers;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;


public class RepositoryNodeSelectorPresenter implements RepositoryNodeSelector,
		ClickHandler, SelectionHandler<NodeData> {

	public interface Display extends IsWidget {
		HasClickHandlers getStartButton();

		<T extends HasClickHandlers, HasSelectionHandlers> List<T> showPath(List<NodeData> nodes);

		<T extends HasClickHandlers, HasSelectionHandlers> List<T> showSubMenu(NodeData parentNode,
				List<NodeData> nodes);
	}

	// Injected
	private final NodesManager nodesManager;
	private final AccountHelper account;
	private final Display display;
	private final HandlerManager eventBus;

	// Selected node
	private NodeData selectedNode;

	@Inject
	public RepositoryNodeSelectorPresenter(Display display, NodesManager nodesManager,
			AccountHelper account) {

		this.eventBus = new HandlerManager(null);
		this.display = display;
		this.nodesManager = nodesManager;
		this.account = account;

		display.getStartButton().addClickHandler(this);
	}

	@Override
	public void go(HasWidgets container) {
		container.clear();
		container.add(display.asWidget());
	}

	@Override
	public NodeData getSelectedNode() {
		return selectedNode;
	}

	@Override
	public GroupIdentity getGroupIdentity() {
		return selectedNode != null ? account.getAccountGroup(selectedNode.getGroupId())
				.getGroupIdentity() : null;
	}

	@Override
	public void setCurrentNode(final NodeData node) {
		this.selectedNode = node;

		if (node.getId() == null) {
			addHandlers( display.showPath( Arrays.asList(node) ) );
		} else {
			// Get nodes
			nodesManager.getPathToNode(node, new AsyncCallback<LinkedList<NodeData>>() {
				@Override
				public void onFailure(Throwable caught) {
				}

				@Override
				public void onSuccess(LinkedList<NodeData> result) {
					// Add group node
					result.addFirst(new NodeDataImpl(null, result.getFirst().getGroupId(), account
							.getAccountGroup(result.getFirst().getGroupId()).getGroupIdentity()
							.getPrintName()));

					// Show result
					addHandlers( display.showPath((List<NodeData>) result) );
				}
			});
		}
	}

	@Override
	public void onClick(ClickEvent event) {
		if (event.getSource().equals(display.getStartButton())) {
			List<NodeData> groups = new ArrayList<NodeData>();

			for (AccountGroup g : account.getAccount().getGroups().getGroupsList()) {
				NodeData node = new NodeDataImpl(null, g.getGroupIdentity().getId(), g.getGroupIdentity()
						.getPrintName());
				groups.add(node);
			}

			addHandlers( display.showSubMenu(null, groups) );
		} else {
			// Get node from layout
			NodeData node = (NodeData) ((Widget) (event.getSource())).getLayoutData();

			// Set as current node
			setCurrentNode(node);
			
			// Fire selection event
			SelectionEvent.fire(this, node);
		}
	}
	
	private void addHandlers(List objs) {
		for (Object obj : objs) {
			((HasClickHandlers) obj).addClickHandler(RepositoryNodeSelectorPresenter.this);
			((HasSelectionHandlers<NodeData>) obj)
					.addSelectionHandler(RepositoryNodeSelectorPresenter.this);
		}		
	}

	@Override
	public void onSelection(SelectionEvent<NodeData> event) {
		// Get selected item
		final NodeData node = event.getSelectedItem();

		// Get nodes in given node
		nodesManager.getSubTree(node.getGroupId(), node.getId(), new AsyncCallback<List<NodeData>>() {
			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(List<NodeData> result) {
				addHandlers( display.showSubMenu(node, result) );
			}
		});
	}

	@Override
	public HandlerRegistration addSelectionHandler(SelectionHandler<NodeData> handler) {
		return eventBus.addHandler(SelectionEvent.getType(), handler);
	}

	@Override
	public void fireEvent(GwtEvent<?> event) {
		eventBus.fireEvent(event);
	}
}
